using Assist;
using System;
using UnityEngine;
using UnityEngine.Rendering;
namespace URP.WarFog
{
    public enum WarFogInitState
    {
        None,
        Loading,
        Completed
    }
    public class WarFogMgr : Singleton<WarFogMgr>
    {
        public WarFogInitState IsInitialized => initialized;
        public Material blitMat;
        public float duration = 1.5f;
        public string default_areaTexRes = "warfog";
        public string default_uvRes = "WarFogUV";
        private RTHandle maskTex1, maskTex2;
        [NonSerialized]
        public Vector4[] datas;
        private WarFog warFog;
        private const string BlitTexName = "WarFogBlittor";
        private const string BlitTexName2 = "WarFogBliter2";
        private WarFogInitState initialized = WarFogInitState.None;

        private float timeStep = 0.1f;
        private float cCountDown;

        private string areaTexRes;
        private string uvRes;

        private void Awake()
        {
            InitWarFogMgr(default_areaTexRes, default_uvRes);
        }
        /// <summary>
        /// ��ʼ��
        /// </summary>
        /// <param name="areaTexRes">��������ͼ����</param>
        /// <param name="uvRes">����UV��������</param>
        /// <returns></returns>
        public bool InitWarFogMgr(string areaTexRes, string uvRes)
        {
            if (this.areaTexRes != areaTexRes || this.uvRes != uvRes)
            {
                ClearFog();
                initialized = WarFogInitState.Loading;
            }
            if (initialized == WarFogInitState.Completed)
                return true;

            var area = Resources.Load<Texture2D>(areaTexRes); 
            OnAreaTexLoaded(area);
            
            var uvs = Resources.Load<WarFogUV>(uvRes);
            datas = uvs.uv;

            OnInitialized();
            
            return false;
        }
        /// <summary>
        /// ����ÿ������仯ֵ�������仯ʱ����Ϊ1
        /// </summary>
        /// <param name="step"></param>
        public void SetFogStep(float step)
        {
            if (initialized != WarFogInitState.Completed)
                return;
            timeStep = duration * step;
            cCountDown = timeStep;
            warFog.SetFogStep(step);
        }
        /// <summary>
        /// ��ɢָ����������
        /// </summary>
        /// <param name="ids"></param>
        public void FogClear(int[] ids, bool immediately = false)
        {
            if (initialized != WarFogInitState.Completed)
                return;
            warFog.FogClear(ids);
            if (immediately)
                ForceRefresh();
        }
        /// <summary>
        /// ��ɢָ����������
        /// </summary>
        /// <param name="id"></param>
        public void FogClear(int id, bool immediately = false)
        {
            if (initialized != WarFogInitState.Completed)
                return;
            warFog.SetFogState(id, true);
            if (immediately)
                ForceRefresh();
        }
        /// <summary>
        /// ����ָ����������
        /// </summary>
        /// <param name="ids"></param>
        public void FogAppear(int[] ids, bool immediately = false)
        {
            if (initialized != WarFogInitState.Completed)
                return;
            warFog.FogAppear(ids);
            if (immediately)
                ForceRefresh();
        }
        /// <summary>
        /// ����ָ����������
        /// </summary>
        /// <param name="id"></param>
        public void FogAppear(int id, bool immediately = false)
        {
            if (initialized != WarFogInitState.Completed)
                return;
            warFog.SetFogState(id, false);
            if (immediately)
                ForceRefresh();
        }
        /// <summary>
        /// ����
        /// </summary>
        public void Reset()
        {
            if (initialized != WarFogInitState.Completed)
                return;
            warFog.Reset();
            ForceRefresh();
        }

        private void ForceRefresh()
        {
            var lastCount = cCountDown;
            cCountDown = timeStep;
            var last = warFog._step;
            warFog.SetFogStep(1);
            Update();
            warFog.SetFogStep(last);
            cCountDown = last;
        }

        private void OnAreaTexLoaded(Texture2D area)
        {
            if (!area)
            {
                Debug.LogError("��������ͼ����ʧ�ܣ�");
                return;
            }
            var width = area.width;
            var height = area.height;
            var format = area.graphicsFormat;
            maskTex1 = RTHandles.Alloc(width, height, colorFormat: format, name: BlitTexName);
            maskTex2 = RTHandles.Alloc(width, height, colorFormat: format, name: BlitTexName2);
            Graphics.Blit(area, maskTex1);
        }

        private void OnInitialized()
        {
            warFog = new WarFog();
            warFog.InitFog(datas);
            //SetFogStep()
            var mat = GetComponent<Renderer>().sharedMaterial;
            mat.mainTexture = maskTex1; // 设定 maskTex1 为当前预制的主贴图（Shader：WarFogBlit.shader）
            initialized = WarFogInitState.Completed;
        }

        // Update is called once per frame
        private void Update()
        {
            if (initialized != WarFogInitState.Completed)
                return;
            cCountDown += Time.deltaTime;
            if (cCountDown < timeStep)
                return;
            cCountDown = 0;
            var buffer = CommandBufferPool.Get("WarFogBlit");
            var dirty = warFog.UpdateWarFog(buffer);
            if (dirty)
            {
                buffer.Blit(maskTex1, maskTex2, blitMat);
                buffer.Blit(maskTex2, maskTex1, blitMat);
                // buffer.SetGlobalTexture("_FogMaskTex", maskTex1); // 没用到，不需要设定为全局，上面已经设置
                Graphics.ExecuteCommandBuffer(buffer);
            }
            CommandBufferPool.Release(buffer);
        }

        private void ClearFog()
        {
            RTHandles.Release(maskTex1);
            RTHandles.Release(maskTex2);
            warFog?.ClearWarFog();
            datas = null;
            initialized = WarFogInitState.None;
            areaTexRes = null;
            uvRes = null;
        }
        private void OnDestroy()
        {
            ClearFog();
        }
    }
}